package com.czl.websocket.server;

import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.czl.common.auth.App;
import com.czl.websocket.bean.Message;
import com.czl.websocket.util.UrlUtil;
import org.apache.commons.lang3.StringUtils;
import org.java_websocket.WebSocket;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.*;


public class ServerDemo extends WebSocketServer {


    public ServerDemo() throws UnknownHostException {
    }

    public ServerDemo(int port) throws UnknownHostException {
        super(new InetSocketAddress("0.0.0.0",port));
        System.out.println("websocket Server start at port:"+port);
    }


    /**
     * 触发连接事件
     */
    @Override
    public void onOpen(WebSocket conn, ClientHandshake clientHandshake) {
        String resourceDescriptor = clientHandshake.getResourceDescriptor();
        System.out.println("req  "+resourceDescriptor);

        String uid = Convert.toStr(UrlUtil.getUrlParams(resourceDescriptor.replace("/?","")).get("uid"),null);
        String appTag = Convert.toStr(UrlUtil.getUrlParams(resourceDescriptor.replace("/?","")).get("appTag"),null);
        String debug = Convert.toStr(UrlUtil.getUrlParams(resourceDescriptor.replace("/?","")).get("__debug"),null);
        String sign = Convert.toStr(UrlUtil.getUrlParams(resourceDescriptor.replace("/?","")).get("sign"),null);

        System.out.println("debug:"+debug+"|uid:"+uid+"|appTag:"+appTag+"|sign:"+sign);
        try {
            //检查签名
            //调试模式 直接 跳过
            if(StringUtils.isNotBlank(debug)&&debug.equals("true")){
                System.out.println("调试模式");
            }else if(appTag==null||"".equals(appTag)||App.TagFIELDS.get(appTag)==null){
                System.out.println("参数错误 appTag不存在");
                //不是调试模式 app标识没传 非法请求 直接关闭连接
                    conn.close();
                    return;
            }else {
                System.out.println("=========开始检查签名");
                //检查签名
                Map<String, Object> urlParams = UrlUtil.getUrlParams(resourceDescriptor.replace("/?", ""));
                TreeMap<String, Object> treeMap = new TreeMap<>();
                urlParams.entrySet().stream().forEach(
                        en->{
                            treeMap.put(en.getKey(), en.getValue());
                        }
                );
                //签名不合法 关闭连接 直接返回
                String sign1 = App.TagFIELDS.get(appTag).getSign(treeMap);
                if(StringUtils.isBlank(sign)||!sign.equals(sign1)){
                    System.out.println("sign参数错误 签名不合法"+"|"+sign+"|"+sign1);
                    conn.close();
                    return;
                }
            }
        } catch (Exception e) {
            System.out.println("================异常==============="+e.getMessage());
        }

        System.out.println("================请求合法===============");





        WebSockeManger.add(conn,uid);

        List<WebSocket> webSocketList = WebSockeManger.getWebSocketList();
        if(webSocketList!=null&&webSocketList.size()>1){
            for (WebSocket webSocket : webSocketList) {

                for (int i = 0; i < 20; i++) {
                    if (webSocket.getReadyState().equals(ReadyState.OPEN)) {
                        break;
                    }
                }

                try {
                    if(webSocket.equals(conn)){
                        webSocket.send("你加入了房间");
                }
                    else{
                    webSocket.send("<"+WebSockeManger.getUid(webSocket)+"> 加入了房间");
                }
                } catch (Exception e) {
                    //连接失败判断为已经退出程序
                    String cuid = WebSockeManger.getUid(webSocket);
                    WebSockeManger.remove(webSocket);
                    System.out.println("发送失败 已退出客户端 ===" +cuid+"=="+ conn.getRemoteSocketAddress().getAddress().getHostAddress());
                }
            }
        }

        System.out.println("new connection ===" +uid+"=="+ conn.getRemoteSocketAddress().getAddress().getHostAddress());
    }

    /**
     *
     * 连接断开时触发关闭事件
     */
    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {

    }

    /**
     * 客户端发送消息到服务器时触发事件
     */
    @Override
    public void onMessage(WebSocket conn, String message) {
        System.out.println("you have a new message: "+ message);

        Message msg = null;
        try {
            msg = Message.getInstance(message);
        } catch (Exception e) {
            System.out.println("消息格式错误:"+message);
        }

        List<WebSocket> webSocketList = WebSockeManger.getWebSocketList();
        if(webSocketList!=null&&webSocketList.size()>0){
            for (WebSocket webSocket : webSocketList) {
                if(webSocket.equals(conn)){
                    msg.setSelf(true);
                }else {
                    msg.setSelf(false);
                }

                for (int i = 0; i < 20; i++) {
                    if (webSocket.getReadyState().equals(ReadyState.OPEN)) {
                        break;
                    }
                }
                try {
                    //向客户端发送消息
                    webSocket.send(JSONUtil.toJsonStr(msg));
                } catch (Exception e) {
                    //连接失败判断为已经退出程序
                    String uid = WebSockeManger.getUid(webSocket);
                    WebSockeManger.remove(webSocket);
                    System.out.println("发送失败 已退出客户端 ===" +uid+"=="+ conn.getRemoteSocketAddress().getAddress().getHostAddress());
                }
            }
        }

    }

    /**
     * 触发异常事件
     */
    @Override
    public void onError(WebSocket conn, Exception e) {
        //e.printStackTrace();
        if( conn != null ) {
            //some errors like port binding failed may not be assignable to a specific websocket
        }
    }

    public void onStart() {

    }

    @Override
    public void start() {
        super.start();

    }

    /**
     * 启动服务端
     * @param args
     * @throws UnknownHostException
     */
    public static void main(String[] args) throws UnknownHostException {
        new ServerDemo(9898).start();
    }
}